package com.xingfly.service;

import com.xingfly.model.BaseModel;
import com.xingfly.model.Event;
import com.xingfly.model.Relation;
import com.xingfly.model.Tag;
import com.xingfly.repository.FeedRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by SuperS on 2016/12/13.
 */
@Service
public class FeedService {
    public static final int FEED_COUNT_PER_PAGE = 10;
    public static final int FEED_COUNT = 200;

    @Autowired
    private FollowService followService;
    @Autowired
    private FeedRepository feedRepository;
    @Autowired
    private EventService eventService;
    @Autowired
    private AccountService accountService;
    @Autowired
    private LikeService likeService;
    @Autowired
    private CommentService commentService;
    @Autowired
    private InterestService interestService;
    @Autowired
    private RelationService relationService;

    /**
     * 推送数据
     *
     * @param userId  用户ID
     * @param eventId 事件ID
     */
    public void push(Long userId, Long eventId) {
        List<Long> followers = followService.getFollowerIds(userId);
        followers.add(userId);//把当前用户也添加进去
        for (Long follower : followers) {
            feedRepository.save("feed:user:" + follower, eventId);
        }
    }

    /**
     * 缓存feed到标签列表序列中
     *
     * @param eventId 事件ID
     * @param tagId   标签ID
     */
    public void cacheFeed2Tag(Long tagId, Long eventId) {
        feedRepository.save("feed:tag:" + tagId, eventId);
    }

    /**
     * 缓存feed到标签列表序列中
     *
     * @param eventsId 事件列表
     * @param tagId    标签ID
     */
    public void cacheFeeds2Tag(Long tagId, List<Long> eventsId) {
        feedRepository.saveAll("feed:tag:" + tagId, eventsId);
    }

    /**
     * 根据userID 分页获取EventIds
     *
     * @param userId 用户Id
     * @param start  开始
     * @param count  每页大小
     */
    public List<Long> getEventIds(Long userId, Long start, Long count) {
        return feedRepository.fetch("feed:user:" + userId, start, count);
    }

    /**
     * 根据用户ID默认分页获取Events
     *
     * @param userId 用户ID
     */
    public List<Event> getFeeds(Long userId) {
        return getFeeds(userId, (long) FEED_COUNT_PER_PAGE);
    }

    /**
     * 根据用户ID分页获取Events
     *
     * @param userId 用户ID
     * @param count  每页大小
     */
    public List<Event> getFeeds(Long userId, Long count) {
        List<Long> eventIds = getEventIds(userId, 0L, count - 1);
        return decorateFeeds(userId, eventIds);
    }

    /**
     * 组装feeds
     *
     * @param userId   用户id
     * @param eventIds 事件ID列表
     */
    private List<Event> decorateFeeds(Long userId, List<Long> eventIds) {
        List<Event> events = new ArrayList<>();
        if (eventIds != null && eventIds.size() != 0) {
            events = eventService.getEventsWithIDs(eventIds);
            updateEventLike(userId, events);
            updateEventComment(events);
        }
        return events;
    }

    /**
     * 更新Event的Comment数量
     *
     * @param events 事件列表
     */
    private void updateEventComment(List<Event> events) {
        if (events == null || events.size() == 0)
            return;
        for (Event event : events) {
            event.setCommentCount((int) commentService.getCommentsCount(event.getObjectType(), event.getObjectId()));
        }
    }

    /**
     * 更新Event的Like相关属性
     *
     * @param userId 用户ID
     * @param events 事件列表
     */
    private void updateEventLike(Long userId, List<Event> events) {
        if (events == null || events.size() == 0)
            return;
        for (Event event : events) {
            event.setLikeCount(Math.toIntExact(likeService.likeCount(event.getObjectType(), event.getObjectId())));
            event.setLike(likeService.isLike(userId, event.getObjectType(), event.getObjectId()));
        }
    }

    /**
     * 根据用户ID分页获取 events
     *
     * @param userId 用户ID
     * @param num    分页的第几页
     */
    public List<Event> getFeedsOfOfPage(Long userId, int num) {
        List<Long> eventIds = feedRepository.fetch("feed:user:" + userId,
                (long) FEED_COUNT_PER_PAGE * (num - 1),
                (long) (FEED_COUNT_PER_PAGE - 1));
        return decorateFeeds(userId, eventIds);
    }

    /**
     * 删除feed
     *
     * @param userId  用户ID
     * @param eventId 事件ID
     */
    public void delete(Long userId, Long eventId) {
        feedRepository.delete("feed:user:" + userId, eventId);
    }

    /**
     * 获取tag标签的feed
     *
     * @param userId 用户ID
     * @param tagId  标签ID
     */
    public List<Event> getFeedsByTag(Long userId, Long tagId) {
        return getFeedsByTag(userId, tagId, FEED_COUNT_PER_PAGE);
    }

    /**
     * 根据标签获取Events
     *
     * @param userId 用户ID
     * @param tagId  标签ID
     * @param count  数量
     */
    public List<Event> getFeedsByTag(Long userId, Long tagId, int count) {
        List<Long> eventIds = getEventIDsByTag(tagId, 0, count - 1);
        return decorateFeeds(userId, eventIds);
    }

    /**
     * 获取Redis缓存中的EventIDs
     *
     * @param tagId 标签ID
     * @param start 开始
     * @param count 数量
     */
    private List<Long> getEventIDsByTag(Long tagId, int start, int count) {
        return feedRepository.fetch("feed:tag:" + tagId, (long) start, (long) count);
    }

    /**
     * feeds推荐
     */
    public List<Event> getRecommendFeeds() {
        return eventService.getEvents(0, 20);
    }

    /**
     * 保存所有eventIds key为 userID
     *
     * @param userId 用户ID
     */
    public void codeStart(Long userId) {
        if (feedRepository.count("feed:user:" + userId) != 0) {
            return;
        }
        List<Tag> tags = interestService.getTagsByUserId(userId);
        List<Relation> relations = relationService.getRelationInTags(tags);
        List<Event> events = eventService.getEventsWithRelations(relations);

        if (events == null || events.size() == 0) {
            events = eventService.getEvents(0, FEED_COUNT_PER_PAGE);
        }

        List<Long> eventIds = events.stream().map(BaseModel::getId).collect(Collectors.toList());
        feedRepository.saveAll("feed:user:" + userId, eventIds);
    }
}
